home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 4 / Example 4.5 / terrain.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-07-01  |  5.9 KB  |  242 lines

  1. #include "terrain.h"
  2.  
  3. const DWORD TERRAINVertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;
  4.  
  5. //////////////////////////////////////////////////////////////////////////////////////////
  6. //                                    PATCH                                                //
  7. //////////////////////////////////////////////////////////////////////////////////////////
  8.  
  9. PATCH::PATCH()
  10. {
  11.     m_pDevice = NULL;
  12.     m_pMesh = NULL;
  13. }
  14. PATCH::~PATCH()
  15. {
  16.     Release();
  17. }
  18.  
  19. void PATCH::Release()
  20. {
  21.     if(m_pMesh != NULL)
  22.         m_pMesh->Release();
  23.     m_pMesh = NULL;
  24. }
  25.  
  26. HRESULT PATCH::CreateMesh(HEIGHTMAP &hm, RECT source, IDirect3DDevice9* Dev)
  27. {
  28.     if(m_pMesh != NULL)
  29.     {
  30.         m_pMesh->Release();
  31.         m_pMesh = NULL;
  32.     }
  33.  
  34.     try
  35.     {
  36.         m_pDevice = Dev;
  37.  
  38.         int width = source.right - source.left;
  39.         int height = source.bottom - source.top;
  40.         int nrVert = (width + 1) * (height + 1);
  41.         int nrTri = width * height * 2;
  42.  
  43.         if(FAILED(D3DXCreateMeshFVF(nrTri, nrVert, D3DXMESH_MANAGED, TERRAINVertex::FVF, m_pDevice, &m_pMesh)))
  44.         {
  45.             debug.Print("Couldn't create mesh for PATCH");
  46.             return E_FAIL;
  47.         }
  48.  
  49.         //Create vertices
  50.         TERRAINVertex* ver = 0;
  51.         m_pMesh->LockVertexBuffer(0,(void**)&ver);
  52.         for(int z=source.top, z0 = 0;z<=source.bottom;z++, z0++)
  53.             for(int x=source.left, x0 = 0;x<=source.right;x++, x0++)
  54.             {
  55.                 D3DXVECTOR3 pos = D3DXVECTOR3(x, hm.m_pHeightMap[x + z * hm.m_size.x], -z);
  56.                 D3DXVECTOR2 uv = D3DXVECTOR2(x * 0.2f, z * 0.2f);
  57.                 ver[z0 * (width + 1) + x0] = TERRAINVertex(pos, uv);
  58.             }
  59.         m_pMesh->UnlockVertexBuffer();
  60.  
  61.         //Calculate Indices
  62.         WORD* ind = 0;
  63.         m_pMesh->LockIndexBuffer(0,(void**)&ind);    
  64.         int index = 0;
  65.  
  66.         for(int z=source.top, z0 = 0;z<source.bottom;z++, z0++)
  67.             for(int x=source.left, x0 = 0;x<source.right;x++, x0++)
  68.             {
  69.                 //Triangle 1
  70.                 ind[index++] =   z0   * (width + 1) + x0;
  71.                 ind[index++] =   z0   * (width + 1) + x0 + 1;
  72.                 ind[index++] = (z0+1) * (width + 1) + x0;        
  73.  
  74.                 //Triangle 2
  75.                 ind[index++] = (z0+1) * (width + 1) + x0;
  76.                 ind[index++] =   z0   * (width + 1) + x0 + 1;
  77.                 ind[index++] = (z0+1) * (width + 1) + x0 + 1;
  78.             }
  79.  
  80.         m_pMesh->UnlockIndexBuffer();
  81.  
  82.         //Set Attributes
  83.         DWORD *att = 0, a = 0;
  84.         m_pMesh->LockAttributeBuffer(0,&att);
  85.  
  86.         for(int z=source.top;z<source.bottom;z++)
  87.             for(int x=source.left;x<source.right;x++)
  88.             {
  89.                 //Calculate quad subsets depending on height
  90.                 int subset;
  91.                 if(hm.m_pHeightMap[x + z * hm.m_size.x] == 0.0f)
  92.                     subset = 0;
  93.                 else if(hm.m_pHeightMap[x + z * hm.m_size.x] <= hm.m_maxHeight * 0.6f)
  94.                     subset = 1;
  95.                 else subset = 2;
  96.                 
  97.                 att[a++] = subset;
  98.                 att[a++] = subset;
  99.             }
  100.  
  101.         m_pMesh->UnlockAttributeBuffer();
  102.  
  103.         //Compute normals
  104.         D3DXComputeNormals(m_pMesh, NULL);
  105.     }
  106.     catch(...)
  107.     {
  108.         debug.Print("Error in PATCH::CreateMesh()");
  109.         return E_FAIL;
  110.     }
  111.  
  112.     return S_OK;
  113. }
  114.  
  115. void PATCH::Render(int texture)
  116. {
  117.     //Draw mesh
  118.     if(m_pMesh != NULL)
  119.         m_pMesh->DrawSubset(texture);
  120. }
  121.  
  122. //////////////////////////////////////////////////////////////////////////////////////////
  123. //                                    TERRAIN                                                //
  124. //////////////////////////////////////////////////////////////////////////////////////////
  125.  
  126. TERRAIN::TERRAIN()
  127. {
  128.     m_pDevice = NULL;
  129. }
  130.  
  131. void TERRAIN::Init(IDirect3DDevice9* Dev, INTPOINT _size)
  132. {
  133.     m_pDevice = Dev;
  134.     m_size = _size;
  135.     m_pHeightMap = NULL;
  136.     GenerateRandomTerrain(3);    
  137.  
  138.     //Load textures
  139.     IDirect3DTexture9* grass = NULL, *water = NULL, *stone = NULL;
  140.     if(FAILED(D3DXCreateTextureFromFile(Dev, "textures/water.jpg", &water)))debug.Print("Could not load water.jpg");
  141.     if(FAILED(D3DXCreateTextureFromFile(Dev, "textures/grass.jpg", &grass)))debug.Print("Could not load grass.jpg");
  142.     if(FAILED(D3DXCreateTextureFromFile(Dev, "textures/stone.jpg", &stone)))debug.Print("Could not load stone.jpg");
  143.     m_textures.push_back(water);
  144.     m_textures.push_back(grass);
  145.     m_textures.push_back(stone);
  146. }
  147.  
  148. void TERRAIN::Release()
  149. {
  150.     for(int i=0;i<m_patches.size();i++)
  151.         if(m_patches[i] != NULL)
  152.             m_patches[i]->Release();
  153.  
  154.     m_patches.clear();
  155.  
  156.     if(m_pHeightMap != NULL)
  157.     {
  158.         m_pHeightMap->Release();
  159.         delete m_pHeightMap;
  160.         m_pHeightMap = NULL;
  161.     }
  162. }
  163.  
  164. void TERRAIN::GenerateRandomTerrain(int numPatches)
  165. {
  166.     try
  167.     {
  168.         Release();
  169.  
  170.         //Create two heightmaps and multiply them
  171.         m_pHeightMap = new HEIGHTMAP(m_size, 15.0f);
  172.         HEIGHTMAP hm2(m_size, 30.0f);
  173.  
  174.         m_pHeightMap->CreateRandomHeightMap(rand()%2000, 2.5f, 0.5f, 8);
  175.         hm2.CreateRandomHeightMap(rand()%2000, 2.5f, 0.7f, 3);
  176.  
  177.         hm2.Cap(hm2.m_maxHeight * 0.4f);
  178.  
  179.         *m_pHeightMap *= hm2;
  180.         hm2.Release();
  181.  
  182.         CreatePatches(numPatches);
  183.     }
  184.     catch(...)
  185.     {
  186.         debug.Print("Error in TERRAIN::GenerateRandomTerrain()");
  187.     }
  188. }
  189.  
  190. void TERRAIN::CreatePatches(int numPatches)
  191. {
  192.     try
  193.     {
  194.         //Clear any old patches
  195.         for(int i=0;i<m_patches.size();i++)
  196.             if(m_patches[i] != NULL)
  197.                 m_patches[i]->Release();
  198.         m_patches.clear();
  199.  
  200.         if(m_pHeightMap == NULL)return;
  201.  
  202.         //Create new patches
  203.         for(int y=0;y<numPatches;y++)
  204.             for(int x=0;x<numPatches;x++)
  205.             {
  206.                 RECT r = {x * (m_size.x - 1) / (float)numPatches, 
  207.                           y * (m_size.y - 1) / (float)numPatches, 
  208.                         (x+1) * (m_size.x - 1) / (float)numPatches,
  209.                         (y+1) * (m_size.y - 1) / (float)numPatches};
  210.                         
  211.                 PATCH *p = new PATCH();
  212.                 p->CreateMesh(*m_pHeightMap, r, m_pDevice);
  213.                 m_patches.push_back(p);
  214.             }
  215.     }
  216.     catch(...)
  217.     {
  218.         debug.Print("Error in TERRAIN::CreatePatches()");
  219.     }
  220. }
  221.  
  222. void TERRAIN::Render()
  223. {
  224.     //Set render states
  225.     m_pDevice->SetRenderState(D3DRS_LIGHTING, true);
  226.     m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);
  227.  
  228.     //Create white material
  229.     D3DMATERIAL9 mtrl;
  230.     mtrl.Ambient = mtrl.Specular = mtrl.Diffuse  = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);
  231.     mtrl.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
  232.     m_pDevice->SetMaterial(&mtrl);
  233.  
  234.     //Render Patches
  235.     for(int t=0;t<3;t++)
  236.     {
  237.         m_pDevice->SetTexture(0, m_textures[t]);
  238.  
  239.         for(int i=0;i<m_patches.size();i++)
  240.             m_patches[i]->Render(t);
  241.     }
  242. }